package wdb

import (
	"gitee.com/snxamdf/wui/logs"
	wutil "gitee.com/snxamdf/wui/util"
	"gitee.com/snxamdf/wui/util/w"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/util"
	"path/filepath"
	"sync"
)

var dbs = sync.Map{}

func __init() {
	for _, v := range databases {
		var p = filepath.Join(path, v) // fmt.Sprintf("%s/%s", path, v)
		logs.Debug("init database by ", p, "success.")
		db, err := leveldb.OpenFile(p, nil)
		if err != nil {
			panic("初始化数据库错误：" + err.Error())
		}
		dbs.Store(v, &DB{
			db: db,
		})
	}
	logs.Info("数据库初始化完成...")
}

type DB struct {
	lock sync.Mutex
	db   *leveldb.DB
}

func GetDB(name string) *DB {
	if db, ok := dbs.Load(name); ok {
		return db.(*DB)
	}
	return nil
}

//增加一个值
func (m *DB) Put(key, value string) error {
	if err := m.db.Put([]byte(key), []byte(value), nil); err != nil {
		logs.Error("Put error: ", err)
		return err
	}
	return nil
}

//根据key前缀获取集合
func (m *DB) GetByPrefix(key string) (result *w.WArray) {
	m.lock.Lock()
	defer m.lock.Unlock()
	if key != "" {
		result = w.NewWArray()
		iter := m.db.NewIterator(util.BytesPrefix([]byte(key)), nil)
		for iter.Next() {
			k := iter.Key()
			v := iter.Value()
			logs.Info("Test:", string(k), string(v))
			var data = w.NewMap()
			data.Put(string(k), string(v))
			result.Add(data)
		}
		iter.Release()
		err := iter.Error()
		if err != nil {
			logs.Error("GetByPrefix Error:", err)
		}
		return result
	}
	return nil
}

//根据key获得一个值
func (m *DB) Get(key string) []byte {
	if data, err := m.db.Get([]byte(key), nil); err != nil {
		logs.Error("DB获取数据错误 key:", key, err)
		return nil
	} else {
		return data
	}
}

//根据key 选择返回指定的子属性
//key的数据结构只能为 [] 或 {} 或 [{},{}]
//否则反回空值
func (m *DB) GetBySub(key string, subs []string) interface{} {
	if data, err := m.db.Get([]byte(key), nil); err != nil {
		logs.Error("DB获取数据错误 key:", key, err)
		return nil
	} else {
		var t interface{}
		if err := wutil.ToObject(data, &t); err != nil {
			logs.Error("字符串转换data失败", err)
			return nil
		}
		var result []interface{}
		switch t.(type) {
		case []interface{}:
			var tmp = t.([]interface{})
			for _, vt := range tmp {
				switch vt.(type) {
				case map[string]interface{}:
					var tmpVt = w.ConvertByMap(vt.(map[string]interface{}))
					if len(subs) > 0 {
						for _, subv := range subs {
							if tmpVt.ContainsKey(subv) {
								result = append(result, tmpVt.Get(subv))
							}
						}
					} else {
						for _, v := range tmpVt {
							result = append(result, v)
						}
					}
				}
			}
		case map[string]interface{}:
			var tmpVt = w.ConvertByMap(t.(map[string]interface{}))
			if len(subs) > 0 {
				for _, subv := range subs {
					if tmpVt.ContainsKey(subv) {
						result = append(result, tmpVt.Get(subv))
					}
				}
			} else {
				for _, v := range tmpVt {
					result = append(result, v)
				}
			}
		}
		if len(result) > 0 {
			return result
		} else {
			return nil
		}
	}
}

func (m *DB) GetString(key string) string {
	if v := m.Get(key); v == nil {
		return ""
	} else {
		return string(v)
	}
}

func (m *DB) Delete(key string) bool {
	if err := m.db.Delete([]byte(key), nil); err != nil {
		logs.Error("Delete error: ", err)
		return false
	} else {
		return true
	}
}

func (m *DB) Has(key string) bool {
	if ok, err := m.db.Has([]byte(key), nil); err != nil {
		logs.Error("Has error: ", err)
		return ok
	} else {
		return ok
	}
}

func (m *DB) SizeOf(start, limit string) int64 {
	sz, err := m.db.SizeOf([]util.Range{
		{Start: []byte(start), Limit: []byte(limit)},
	})
	if err != nil {
		logs.Error("SizeOf error: ", err)
	}
	return sz.Sum()
}
